package com.forkjoin;

import org.junit.Test;

import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
import java.util.stream.Collectors;

/**
 * ForkJoin  ,并行执行任务，提升效率
 * 拆分任务的思想（工作窃取）
 * <p>
 * 例：求和计算的任务
 * <p>
 * 使用ForkJoin
 * 1、用ForkJoinPool来执行；forkJoinPool.execute(ForkJoinTask<?> task)
 * 2、计算类要继承RecursiveTask<>
 */
public class ForkJoinDemo extends RecursiveTask<Long> {

	private Long start;
	private Long end;

	// 临界值
	private Long temp = new Integer(2).longValue();

	public ForkJoinDemo(Long start, Long end) {
		this.start = start;
		this.end = end;
	}

	public static void main(String[] args) throws ExecutionException, InterruptedException {

		Long start = 0L;
		Long end = 10L;

		// Long sum = 0L;
		// long l1 = System.currentTimeMillis();
		// sum = add(start, end);
		// long l2 = System.currentTimeMillis();
		// System.out.println("for循环方式计算完成，耗时" + (l2 - l1) + ", 结果:" + sum);

		// 使用forkJoin
		long l3 = System.currentTimeMillis();
		ForkJoinDemo forkJoinDemo = new ForkJoinDemo(start, end);

		ForkJoinPool forkJoinPool = new ForkJoinPool();

		ForkJoinTask<Long> submit = forkJoinPool.submit(forkJoinDemo);
		Long result = submit.join();
		long l4 = System.currentTimeMillis();
		System.out.println("forkJoin计算完成，耗时" + (l4 - l3) + ", 结果:" + result);
	}

	@Test
	public void test() {
		ArrayList<Integer> list = new ArrayList<>();
		for (int i = 0; i < 200000; i++) {
			list.add(i);
		}

	}

	@Override
	protected Long compute() {
		if (end - start < temp) {
			// 分支合并计算
			Long sum = add(start, end);
			return sum;
		} else {
			// 拆分任务，把任务压入线程队列 （把任务放进ForkJoinPool的工作队列）

			Long middle = (start + end) / 2;
			ForkJoinDemo task1 = new ForkJoinDemo(start, middle);
			ForkJoinDemo task2 = new ForkJoinDemo(middle + 1, end);
			System.out.println(Thread.currentThread() + " 任务1 执行");
			task1.fork();
			System.out.println(Thread.currentThread() + " 任务2 执行");
			task2.fork();

			Long result1 = task1.join();
			Long result2 = task2.join();
			return result1 + result2;

		}
	}

	public static long add(long start, long end) {
		long sum = 0;
		for (long i = start; i <= end; i++) {
//            sum += i;
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		return sum;
	}
}
